package top.lixunda.ecommerce.server.user.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import top.lixunda.commerce.common.core.entity.MessageObject;
import top.lixunda.common.utils.ObjectValidators;
import top.lixunda.ecommerce.server.business.BaseServiceImpl;
import top.lixunda.ecommerce.server.business.api.entity.BusinessConstants;
import top.lixunda.ecommerce.server.business.api.entity.BusinessKeyConstants;
import top.lixunda.ecommerce.server.business.api.entity.cache.*;
import top.lixunda.ecommerce.server.business.api.entity.dto.PageDTO;
import top.lixunda.ecommerce.server.good.api.entity.db.StoreDO;
import top.lixunda.ecommerce.server.good.api.entity.dto.StoreInfoQueryDTO;
import top.lixunda.ecommerce.server.good.api.feign.IFeignStoreController;
import top.lixunda.ecommerce.server.user.api.entity.db.AccountDO;
import top.lixunda.ecommerce.server.user.api.entity.db.StaffDO;
import top.lixunda.ecommerce.server.user.api.entity.db.UserDetailDO;
import top.lixunda.ecommerce.server.user.api.entity.db.UserInfoDO;
import top.lixunda.ecommerce.server.user.api.entity.dto.AccountQueryDTO;
import top.lixunda.ecommerce.server.user.mapper.AccountMapper;
import top.lixunda.ecommerce.server.user.mapper.UserInfoMapper;
import top.lixunda.ecommerce.server.user.service.IAccountService;
import top.lixunda.ecommerce.server.user.service.IStaffService;
import top.lixunda.ecommerce.server.user.service.IUserDetailService;
import top.lixunda.ecommerce.server.user.service.IUserService;
import top.lixunda.ecommerce.server.user.utils.JwtTokenUtil;

import java.util.List;

/**
 * <p>
 * 用户账户，此账户为本系统用于唯一标识一个用户，包含密码和密码提示等基本信息。 服务实现类
 * </p>
 *
 * @author Xumda
 * @since 2019-11-19
 */
@Service
public class AccountServiceImpl extends BaseServiceImpl<AccountMapper, AccountDO>
        implements IAccountService {

    private final UserInfoMapper userInfoMapper;

    private final IUserService userService;

    private final IUserDetailService userDetailService;

    private final IStaffService staffService;

    private final IFeignStoreController storeController;

    @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
    @Autowired
    public AccountServiceImpl(UserInfoMapper userInfoMapper,
                              IUserService userService,
                              IUserDetailService userDetailService,
                              IStaffService staffService,
                              IFeignStoreController storeController) {
        this.userInfoMapper = userInfoMapper;
        this.userService = userService;
        this.userDetailService = userDetailService;
        this.staffService = staffService;
        this.storeController = storeController;
    }

    /**
     * 根据id查询账户数据
     *
     * @param accountId 账户编号
     * @return 账户信息
     */
    @Override
    public AccountDO queryAccountById(String accountId) {
        if (ObjectValidators.isEmpty(accountId)) {
            throw getAppException("账户编号不能为空");
        }
        AccountDO accountDO = this.getById(accountId);
        if (ObjectValidators.isEmpty(accountDO)) {
            throw getAppException("查询账户数据失败！账户不存在");
        }
        return accountDO;
    }

    /**
     * 条件查询账户数据
     *
     * @param accountQueryDTO 条件查询信息
     * @return 账户列表
     */
    @Override
    public List<AccountDO> queryAccountByWrapper(AccountQueryDTO accountQueryDTO) {
        if (ObjectValidators.isEmpty(accountQueryDTO)) {
            throw getAppException("条件参数不能为空");
        }
        return this.list(accountQueryDTO.toWrapper());
    }

    /**
     * 分页条件查询用户数据
     *
     * @param pageDTO 添加分页数据
     * @return 账户分页数据
     */
    @Override
    public IPage<AccountDO> queryAccountByPageWrapper(PageDTO<AccountDO, AccountQueryDTO> pageDTO) {
        if (ObjectValidators.isEmpty(pageDTO)) {
            throw getAppException("分页条件参数不能为空");
        }
        return this.page(pageDTO.getPage(), pageDTO.getWrapper());
    }

    /**
     * 使用token进行登录
     *
     * @param token token字符串
     * @return 返回去除密码账户信息，登陆失败时返回Object为Null
     */
    @Override
    public UserDetailDO loginByTokenString(String token) {
        //0. 验证参数
        if (ObjectValidators.isEmpty(token)) {
            throw getAppException("登陆错误！参数token不能为空!");
        }
        //1. 验证token有效性
        if (JwtTokenUtil.isExpiration(token)) {
            throw getAppException("token过期！请重新登陆！");
        }
        //2. 获取用户信息
        UserDetailDO userDetail = userDetailService.getOne(
                new LambdaQueryWrapper<UserDetailDO>()
                        .eq(UserDetailDO::getToken, token)
                        .eq(UserDetailDO::getForbidden, BusinessConstants.FORBIDDEN_NORMAL), false);
        //3. 检验用户存在可用性
        if (ObjectValidators.isEmpty(userDetail) || ObjectValidators.isEmpty(userDetail.getAccount()) || userDetail.getAccount() <= 0) {
            throw getAppException("用户不存在或不可用!");
        }
        //4. 检验密码错误锁定
        String msg = userService.isLock(userDetail);
        if (msg != null) {
            throw getAppException("登陆错误！" + msg);
        }
        //5. 保存日志
        userService.insertLoginLog(userDetail, true);
        //6. 保存用户信息到session中
        saveLoginUserToSession(userDetail);
        //7. 清理密码，返回结果
        UserDetailDO result = userDetail.copy();
        result.setPassword(null);
        return result;
    }

    /**
     * 将登陆用户数据保存到session中
     *
     * @param userDetail UserDetailDO
     */
    @Override
    public void saveLoginUserToSession(UserDetailDO userDetail) {
        CacheLoginUser cacheLoginUser = new CacheLoginUser();
        UserInfoDO userInfoDO = userInfoMapper.selectById(userDetail.getAccount());
        // 创建userName，以firstName+lastName为主，nickName为辅
        String userName = "";
        if (ObjectValidators.isEmpty(userInfoDO)) {
            throw getAppException("保存登陆缓存失败！用户基本信息为空！");
        }
        if (ObjectValidators.isNotEmpty(userInfoDO.getFirstName())) {
            userName += userInfoDO.getFirstName();
        }
        if (ObjectValidators.isNotEmpty(userInfoDO.getLastName())) {
            userName += userInfoDO.getLastName();
        }
        if (ObjectValidators.isEmpty(userName)) {
            userName = ObjectValidators.isEmpty(userInfoDO.getNickname()) ? ""
                    : userInfoDO.getNickname();
        }
        BeanUtils.copyProperties(userDetail, cacheLoginUser);
        cacheLoginUser.setName(userName);
        cacheLoginUser.setType(userDetail.getUserType());
        saveLoginUserCache(cacheLoginUser);
        switch (userDetail.getUserType()) {
            case BusinessConstants.USER_TYPE_USER:
                CacheUser cacheUser = new CacheUser();
                BeanUtils.copyProperties(userDetail, cacheUser);
                cacheUser.setName(userName);
                saveUserCache(cacheUser);

                getHttpSessionProxy().removeAttribute(BusinessKeyConstants.SESSION_CACHE_STORE);
                getHttpSessionProxy().removeAttribute(BusinessKeyConstants.SESSION_CACHE_STORE_USER);
                getHttpSessionProxy().removeAttribute(BusinessKeyConstants.SESSION_CACHE_ADMIN_USER);
                break;
            case BusinessConstants.USER_TYPE_STORE:
                // 保存店铺用户数据
                CacheStoreUser cacheStoreUser = new CacheStoreUser();
                BeanUtils.copyProperties(userDetail, cacheStoreUser);
                cacheStoreUser.setName(userName);
                saveStoreUserCache(cacheStoreUser);
                // 保存店铺数据
                StaffDO staffDO = staffService.getOne(new LambdaQueryWrapper<StaffDO>()
                        .eq(StaffDO::getUserId, cacheStoreUser.getAccount())
                        .eq(StaffDO::getUserType, userDetail.getUserType()), false);
                if (ObjectValidators.isEmpty(staffDO)) {
                    throw getAppException("查询店铺员工信息失败：员工信息不存在！");
                }
                // 查询店铺信息
                StoreInfoQueryDTO storeInfoQueryDTO = new StoreInfoQueryDTO();
                storeInfoQueryDTO.setState(StoreDO.STATE_NORMAL)
                        .setId(staffDO.getSystemId());
                PageDTO<StoreDO, StoreInfoQueryDTO> pageDTO = new PageDTO<>();
                pageDTO.setCurrent(1L)
                        .setSize(1L)
                        .setCondition(storeInfoQueryDTO);
                MessageObject<Page<StoreDO>> storeResponse = storeController.queryStoreInfoByPageWrapper(pageDTO);
                if (storeResponse.isNotSuccess()) {
                    throw getAppException("查询店铺信息失败：" + storeResponse.getMsg());
                }
                IPage<StoreDO> storePage = storeResponse.getObject();
                if (ObjectValidators.isEmpty(storePage) || ObjectValidators.isEmpty(storePage.getRecords())) {
                    throw getAppException("查询店铺信息失败：店铺信息不存在！");
                }
                CacheStore cacheStore = new CacheStore();
                BeanUtils.copyProperties(storePage.getRecords().get(0), cacheStore);
                saveStoreCache(cacheStore);

                getHttpSessionProxy().removeAttribute(BusinessKeyConstants.SESSION_CACHE_ADMIN_USER);
                getHttpSessionProxy().removeAttribute(BusinessKeyConstants.SESSION_CACHE_USER);
                break;
            case BusinessConstants.USER_TYPE_ADMIN:
                CacheAdminUser cacheAdminUser = new CacheAdminUser();
                BeanUtils.copyProperties(userDetail, cacheAdminUser);
                cacheAdminUser.setName(userName);
                saveAdminUserCache(cacheAdminUser);

                getHttpSessionProxy().removeAttribute(BusinessKeyConstants.SESSION_CACHE_STORE);
                getHttpSessionProxy().removeAttribute(BusinessKeyConstants.SESSION_CACHE_STORE_USER);
                getHttpSessionProxy().removeAttribute(BusinessKeyConstants.SESSION_CACHE_USER);
                break;
            default:
                throw getAppException("系统错误！错误的用户数据！不存在的用户类型！");
        }
    }
}
